import { defined } from '../../Source/Cesium.js';
import { GeographicTilingScheme } from '../../Source/Cesium.js';
import { QuadtreeTile } from '../../Source/Cesium.js';
import { QuadtreeTileLoadState } from '../../Source/Cesium.js';
import { TileReplacementQueue } from '../../Source/Cesium.js';

describe('Scene/TileReplacementQueue', function() {

    function Tile(num, loadedState, upsampledState) {
        this._num = num;
        this.state = QuadtreeTileLoadState.LOADING;
        this.data = {};
        this.data.imagery = [];
        if (defined(loadedState)) {
            this.data.loadedTerrain = {
                state : loadedState
            };
        }
        if (defined(upsampledState)) {
            this.data.upsampledTerrain = {
                state : upsampledState
            };
        }
        this.eligibleForUnloading = true;
    }

    Tile.prototype.freeResources = function() {

    };

    var queue;
    var one;
    var two;
    var three;
    var four;
    var notEligibleForUnloading;
    beforeEach(function() {
        var tilingScheme = new GeographicTilingScheme();
        queue = new TileReplacementQueue();
        one = new QuadtreeTile({
            tilingScheme : tilingScheme,
            level : 0,
            x : 0,
            y : 0
        });
        two = new QuadtreeTile({
            tilingScheme : tilingScheme,
            level : 0,
            x : 1,
            y : 0
        });
        three = new QuadtreeTile({
            tilingScheme : tilingScheme,
            level : 1,
            x : 0,
            y : 0
        });
        four = new QuadtreeTile({
            tilingScheme : tilingScheme,
            level : 1,
            x : 2,
            y : 1
        });
        notEligibleForUnloading = new QuadtreeTile({
            tilingScheme : tilingScheme,
            level : 1,
            x : 2,
            y : 1
        });
        notEligibleForUnloading.data = {
            eligibleForUnloading : false
        };
    });

    describe('markStartOfRenderFrame', function() {
        it('prevents tiles added afterward from being trimmed.', function() {
            queue.markTileRendered(one);
            queue.markTileRendered(two);
            queue.markStartOfRenderFrame();

            queue.markTileRendered(three);

            queue.trimTiles(0);

            expect(queue.count).toEqual(1);
            expect(queue.head).toEqual(three);
        });

        it('prevents all tiles from being trimmed if called on an empty queue.', function() {
            queue.markStartOfRenderFrame();

            queue.markTileRendered(one);
            queue.markTileRendered(two);
            queue.markTileRendered(three);

            queue.trimTiles(0);
            expect(queue.count).toEqual(3);
        });

        it('adjusts properly when last tile in previous frame is moved to the head.', function() {
            queue.markTileRendered(one);
            queue.markTileRendered(two);
            queue.markTileRendered(three);

            queue.markStartOfRenderFrame();

            queue.markTileRendered(three);

            queue.trimTiles(0);
            expect(queue.count).toEqual(1);
            expect(queue.head).toEqual(three);
        });

        it('adjusts properly when all tiles are moved to the head.', function() {
            queue.markTileRendered(one);
            queue.markTileRendered(two);
            queue.markTileRendered(three);

            queue.markStartOfRenderFrame();

            queue.markTileRendered(one);
            queue.markTileRendered(two);
            queue.markTileRendered(three);

            queue.trimTiles(0);
            expect(queue.count).toEqual(3);
            expect(queue.head).toEqual(three);
            expect(queue.tail).toEqual(one);
        });
    });

    describe('trimTiles', function() {
        it('does not remove a tile that is not eligible for unloading.', function() {
            queue.markTileRendered(one);
            queue.markTileRendered(two);
            queue.markTileRendered(notEligibleForUnloading);
            queue.markTileRendered(three);

            queue.markStartOfRenderFrame();

            queue.trimTiles(0);
            expect(queue.count).toEqual(1);
            expect(queue.head).toEqual(notEligibleForUnloading);
        });

        it('does not remove a transitioning tile at the end of the last render frame.', function() {
            queue.markTileRendered(one);
            queue.markTileRendered(two);
            queue.markTileRendered(three);
            queue.markTileRendered(notEligibleForUnloading);

            queue.markStartOfRenderFrame();

            queue.trimTiles(0);
            expect(queue.count).toEqual(1);
            expect(queue.head).toEqual(notEligibleForUnloading);
        });

        it('removes two tiles not used last render frame.', function() {
            queue.markTileRendered(notEligibleForUnloading);
            queue.markTileRendered(one);
            queue.markTileRendered(two);
            queue.markStartOfRenderFrame();
            queue.markTileRendered(three);
            queue.markTileRendered(four);
            queue.trimTiles(0);
            expect(queue.count).toEqual(3);
        });
    });
});
